﻿namespace DCHealthCheck.MvcWeb.Classes.DataServices {

    #region Usings
    using DCHealthCheck.Common;
    using DCHealthCheck.DomainModel;
    using DCHealthCheck.MvcWeb.Classes.ViewModels;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Text;
    using System.Threading;
    using System.Web;
    #endregion

    public class ResultsDataService : BaseDataService, IResultsDataService {

        #region Members
        private readonly IRepository<SystemInfo, IEntityManager> ResultsRepository;

        private readonly Expression<Func<SystemInfo, object>>[] SystemInfoIncludedEntities;
        #endregion

        #region Constructor
        public ResultsDataService(
            IRepository<DomainController, IEntityManager> dcRepository,
            IRepository<SystemInfo, IEntityManager> resultsRepository): base(dcRepository) {
                if (resultsRepository == null) {
                    throw new ArgumentNullException("resultsRepository");
                }

            this.ResultsRepository = resultsRepository;
            this.SystemInfoIncludedEntities = new Expression<Func<SystemInfo, object>>[] {
                // parent entities
                (x) => x.DomainController,
                (x) => x.HealthCheckSummary,
                // child entities
                (x) => x.GroupPolicySysvolInfo,
                (x) => x.InstalledProducts,
                (x) => x.NetstatInfos,
                (x) => x.PendingReplications,
                (x) => x.ProcessInfos,
                (x) => x.ReplicationNeighbors,
                (x) => x.RoleFeatures,
                (x) => x.ServiceInfos,
                (x) => x.TagObjectValues,
                (x) => x.TagObjectValues.Select(y => y.TagObject),
                (x) => x.TimeSyncInfo
            };
        }
        #endregion

        #region Methods
        public string GetCSVData(ResultsViewModel viewModel) {
            if (viewModel == null) {
                throw new ArgumentNullException("viewModel");
            }
            viewModel.Initialize();
            viewModel.SkipCount = 0;
            viewModel.TakeCount = int.MaxValue;
            this.ProcessData(viewModel, false, false);

            var fileData = new StringBuilder();
            fileData.AppendLine(SystemInfo.CSVHeader);
            foreach (var systemInfo in viewModel.Results) {
                fileData.AppendLine(systemInfo.ToCSVString());
            }

            return fileData.ToString();
        }

        private IQueryable<SystemInfo> GetFilteredResults(ResultsViewModel viewModel) {

            var results = this.ResultsRepository.Get(this.SystemInfoIncludedEntities);

            if ((viewModel.SystemInfoId != Guid.Empty)) {
                results = results
                    .Where(x => x.Id == viewModel.SystemInfoId);
            }
            else {
                if ((viewModel.DomainControllerId != Guid.Empty)) {
                    results = results
                        .Where(x => x.DomainController.Id == viewModel.DomainControllerId);
                }
                else {
                    if (viewModel.Date != DateTime.MinValue) {
                        results = results.Where(x => (x.CheckDateTimeUTC == viewModel.Date));
                    }
                    else {
                        if (viewModel.StartDate.HasValue) {
                            results = results.Where(x => x.CheckDateUTC >= viewModel.StartDate);
                        }
                        if (viewModel.EndDate.HasValue) {
                            results = results.Where(x => x.CheckDateUTC <= viewModel.EndDate);
                        }
                    }
                    if (!string.IsNullOrWhiteSpace(viewModel.Domain)) {
                        results = results.Where(x => x.DomainController.NetbiosDomain.ToUpper() == viewModel.Domain.ToUpper());
                    }

                    if (!string.IsNullOrWhiteSpace(viewModel.ADSite)) {
                        results = results.Where(x => x.DomainController.ADSite.ToUpper() == viewModel.ADSite.ToUpper());
                    }

                    if (!string.IsNullOrWhiteSpace(viewModel.OSVersion)) {
                        results = results.Where(x => x.DomainController.OSVersion.ToUpper() == viewModel.OSVersion.ToUpper());
                    }

                    if (!string.IsNullOrWhiteSpace(viewModel.DCName)) {
                        results = results.Where(x => x.DomainController.SamAccountName.ToUpper().StartsWith(viewModel.DCName));
                    }
                }
            }

            return results;
        }

        public void ProcessData(ResultsViewModel viewModel, bool initialize = true, bool buildFilterSelectLists = true) {
            Global.DefaultLog.DebugFormat("[ThreadId: {0}] {1}", Thread.CurrentThread.ManagedThreadId, Extensions.CurrentMethodName());

            if (viewModel == null) {
                throw new ArgumentNullException("viewModel");
            }

            try {
                if (initialize) {
                    viewModel.Initialize();
                }

                var results = this.GetFilteredResults(viewModel);

                viewModel.DisplayTotalResults = results.Count();

                #region Skip count, take, and sorting
                if (!string.IsNullOrWhiteSpace(viewModel.SortColumn)) {
                    if (viewModel.CurrentSortDirection == System.Web.Helpers.SortDirection.Ascending) {
                        viewModel.Results = results
                            .OrderBy(viewModel.SortColumn)
                            .Skip(viewModel.SkipCount.Value)
                            .Take(viewModel.TakeCount.Value)
                            .ToList();
                    }
                    else {
                        if (viewModel.SortColumn == "ErrorMessage") {
                            viewModel.Results = results
                                .OrderByDescending(viewModel.SortColumn)
                                .ThenBy("DomainController.DNSName")
                                .Skip(viewModel.SkipCount.Value)
                                .Take(viewModel.TakeCount.Value)
                                .ToList();
                        }
                        else {
                            viewModel.Results = results
                                .OrderByDescending(viewModel.SortColumn)
                                .Skip(viewModel.SkipCount.Value)
                                .Take(viewModel.TakeCount.Value)
                                .ToList();
                        }
                    }
                }
                else {
                    viewModel.Results = results
                        .OrderByDescending(x => x.DomainController.SamAccountName)
                        .Skip(viewModel.SkipCount.Value)
                        .Take(viewModel.TakeCount.Value)
                        .ToList();
                }
                #endregion

                viewModel.GetPageCounts();

                if (buildFilterSelectLists) {
                    var filteredDCIds = this.GetFilteredResults(viewModel)
                        .Select(x => x.DomainController.Id)
                        .Distinct()
                        .ToList();

                    this.BuildFilterSelectLists(filteredDCIds, viewModel);
                }
            }
            catch (Exception e) {
                Global.DefaultLog.ErrorFormat("[ThreadId: {0}] {1} {2}", Thread.CurrentThread.ManagedThreadId, Extensions.CurrentMethodName(), e.VerboseExceptionString());
                throw;
            }
        }
        #endregion
    }
}